import mapboxgl from 'mapbox-gl';

export default class MiniMap {
  constructor(options) {
    this.options = {
      id: "mapboxgl-minimap",
      width: "320px",
      height: "180px",
      style: "mapbox://styles/mapbox/streets-v8",
      center: [0, 0],
      zoom: 6,

      // should be a function; will be bound to Minimap
      zoomAdjust: null,

      // if parent map zoom >= 18 and minimap zoom >= 14, set minimap zoom to 16
      zoomLevels: [
        [18, 14, 16],
        [16, 12, 14],
        [14, 10, 12],
        [12, 8, 10],
        [10, 6, 8]
      ],

      lineColor: "#08F",
      lineWidth: 1,
      lineOpacity: 1,

      fillColor: "#F80",
      fillOpacity: 0.25,

      dragPan: false,
      scrollZoom: false,
      boxZoom: false,
      dragRotate: false,
      keyboard: false,
      doubleClickZoom: false,
      touchZoomRotate: false,
      showPointLayers: [],
    }

    this._ticking = false;
    this._lastMouseMoveEvent = null;
    this._parentMap = null;
    this._isDragging = false;
    this._isCursorOverFeature = false;
    this._previousPoint = [0, 0];
    this._currentPoint = [0, 0];
    this._trackingRectCoordinates = [[[], [], [], [], []]];

    Object.assign(this.options, options);
  }

  onRemove() {
    if(!this._container){
      return
    }
    if(this._updateMethods){
      this._parentMap.off("move", this._updateMethods);
      this._updateMethods=null;
    }
    this._container.parentNode.removeChild(this._container);
    this._miniMap = undefined;
    this._container=null;
  }

  onAdd(parentMap) {
    this._parentMap = parentMap;

    let opts = this.options;
    let container = this._container = this._createContainer(parentMap);
    let miniMap = this._miniMap = new mapboxgl.Map({
      attributionControl: false,
      container: container,
      style: this._parentMap.getStyle(),
      zoom: opts.zoom,
      center: opts.center,
      transformRequest: this._parentMap._requestManager._transformRequestFn
    });

    if (opts.maxBounds) miniMap.setMaxBounds(opts.maxBounds);
    console.log(this._parentMap.getStyle());
    miniMap.on("load", this._load.bind(this));

    return this._container;
  }


  _update(e) {
    if (this._isDragging) {
      return;
    }

    let parentBounds = this._parentMap.getBounds();

    this._setTrackingRectBounds(parentBounds);

    if (typeof this.options.zoomAdjust === "function") {
      this.options.zoomAdjust();
    }
  }
  _load()
  {
    let opts = this.options;
    let parentMap = this._parentMap;
    let miniMap = this._miniMap;
    let interactions = [
      "dragPan", "scrollZoom", "boxZoom", "dragRotate",
      "keyboard", "doubleClickZoom", "touchZoomRotate"
    ];

    interactions.forEach(function(i){
      if( opts[i] !== true ) {
        miniMap[i].disable();
      }
    });

    if( typeof opts.zoomAdjust === "function" ) {
      this.options.zoomAdjust = opts.zoomAdjust.bind(this);
    } else if( opts.zoomAdjust === null ) {
      this.options.zoomAdjust = this._zoomAdjust.bind(this);
    }

    let bounds = miniMap.getBounds();

    this._convertBoundsToPoints(bounds);

    miniMap.addSource("trackingRect", {
      "type": "geojson",
      "data": {
        "type": "Feature",
        "properties": {
          "name": "trackingRect"
        },
        "geometry": {
          "type": "Polygon",
          "coordinates": this._trackingRectCoordinates
        }
      }
    });

    miniMap.addLayer({
      "id": "trackingRectOutline",
      "type": "line",
      "source": "trackingRect",
      "layout": {},
      "paint": {
        "line-color": opts.lineColor,
        "line-width": opts.lineWidth,
        "line-opacity": opts.lineOpacity
      }
    });

    // needed for dragging
    miniMap.addLayer({
      "id": "trackingRectFill",
      "type": "fill",
      "source": "trackingRect",
      "layout": {},
      "paint": {
        "fill-color": opts.fillColor,
        "fill-opacity": opts.fillOpacity
      }
    });

    this._trackingRect = this._miniMap.getSource("trackingRect");

    this._update();
    this._updateMethods=()=>{
      this._update()
    };
    parentMap.on("move", this._updateMethods);

    miniMap.on("mousemove", this._mouseMove.bind(this));
    miniMap.on("mousedown", this._mouseDown.bind(this));
    miniMap.on("mouseup", this._mouseUp.bind(this));

    miniMap.on("touchmove", this._mouseMove.bind(this));
    miniMap.on("touchstart", this._mouseDown.bind(this));
    miniMap.on("touchend", this._mouseUp.bind(this));

    this._miniMapCanvas = miniMap.getCanvasContainer();
    this._miniMapCanvas.addEventListener("wheel", this._preventDefault);
    this._miniMapCanvas.addEventListener("mousewheel", this._preventDefault);

    for (let i = 0; i <this.options.showPointLayers.length ; i++) {
      this.addPointLayer(this.options.showPointLayers[i],this.options.showPointLayers[i]+"鹰眼图",18,11)
    }
  }
  addPointLayer(srcLayerName,targetLayerName,maxZoom,minZoom) {
    let miniMap = this._miniMap;
    if(!miniMap){
      throw new Error("地图对象不能为空")
    }
    let srcLayer=miniMap.getLayer(srcLayerName);
    if(!srcLayer){
      throw new Error(srcLayerName+"原图层不存在")
    }
    if(miniMap.getLayer(targetLayerName)){
      throw new Error(targetLayerName+"图层已存在")
    }
    miniMap.addLayer({
      id:targetLayerName,
      type:"circle",
      "source": srcLayer.source,
      "source-layer": srcLayer.sourceLayer,
      "minzoom": minZoom||srcLayer.minzoom||1,
      "maxzoom": maxZoom||srcLayer.maxzoom||18,
      layout: {},
      paint: {
        "circle-radius": 5,
        "circle-color": "#F9CB11",
      },
    });
    let filter= this._parentMap.getFilter(srcLayerName);
    if(filter){
      miniMap.setFilter(targetLayerName,filter);
    }
  }
  _mouseDown ( e )
  {
    if( this._isCursorOverFeature )
    {
      this._isDragging = true;
      this._previousPoint = this._currentPoint;
      this._currentPoint = [e.lngLat.lng, e.lngLat.lat];
    }
  }

  _mouseMove (e)
  {
    this._ticking = false;

    let miniMap = this._miniMap;
    let features = miniMap.queryRenderedFeatures(e.point, {
      layers: ["trackingRectFill"]
    });

    // don't update if we're still hovering the area
    if( ! (this._isCursorOverFeature && features.length > 0) )
    {
      this._isCursorOverFeature = features.length > 0;
      this._miniMapCanvas.style.cursor = this._isCursorOverFeature ? "move" : "";
    }

    if( this._isDragging )
    {
      this._previousPoint = this._currentPoint;
      this._currentPoint = [e.lngLat.lng, e.lngLat.lat];

      let offset = [
        this._previousPoint[0] - this._currentPoint[0],
        this._previousPoint[1] - this._currentPoint[1]
      ];

      let newBounds = this._moveTrackingRect(offset);

      this._parentMap.fitBounds(newBounds, {
        duration: 80,
        noMoveStart: true
      });
    }
  }
  _mouseUp() {
    this._isDragging = false;
    this._ticking = false;
  }

  _moveTrackingRect(offset) {
    let source = this._trackingRect;
    let data = source._data;
    let bounds = data.properties.bounds;

    bounds._ne.lat -= offset[1];
    bounds._ne.lng -= offset[0];
    bounds._sw.lat -= offset[1];
    bounds._sw.lng -= offset[0];

    this._convertBoundsToPoints(bounds);
    source.setData(data);

    return bounds;
  }

  _setTrackingRectBounds(bounds) {
    let source = this._trackingRect;
    let data = source._data;

    data.properties.bounds = bounds;
    this._convertBoundsToPoints(bounds);
    source.setData(data);
  }

  _convertBoundsToPoints(bounds) {
    let ne = bounds._ne;
    let sw = bounds._sw;
    let trc = this._trackingRectCoordinates;

    trc[0][0][0] = ne.lng;
    trc[0][0][1] = ne.lat;
    trc[0][1][0] = sw.lng;
    trc[0][1][1] = ne.lat;
    trc[0][2][0] = sw.lng;
    trc[0][2][1] = sw.lat;
    trc[0][3][0] = ne.lng;
    trc[0][3][1] = sw.lat;
    trc[0][4][0] = ne.lng;
    trc[0][4][1] = ne.lat;
  }


  _zoomAdjust() {
    let miniMap = this._miniMap;
    let parentMap = this._parentMap;
    let miniZoom = parseInt(miniMap.getZoom(), 10);

    if (parentMap.getZoom() >= 3) {
      miniMap.setZoom(parentMap.getZoom() - 3);
    } else {
      miniMap.setZoom(0);
    }
    miniMap.setCenter(parentMap.getCenter());

    // if ( miniZoom !== this.options.zoom) {
    //   if (typeof this.options.bounds === "object") {
    //     miniMap.fitBounds(this.options.bounds, {duration: 50});
    //   }
    //
    //   miniMap.setZoom(this.options.zoom)
    // }
  }


  _createContainer(parentMap) {
    let opts = this.options;
    let container = document.createElement("div");

    container.className = "mapboxgl-ctrl-minimap mapboxgl-ctrl";
    container.setAttribute('style', 'width: ' + opts.width + '; height: ' + opts.height + ';border: 8px solid #1b2431');
    container.addEventListener("contextmenu", this._preventDefault);
    container.style.visibility = "visible";

    // 添加关闭按钮
    let cloBtn = document.createElement("div");
    cloBtn.id = "cloBtn";
    cloBtn.style = `height:15px;width:15px;margin:0;padding:9;background-color:red;text-align:center;cursor:pointer;
                position:absolute;z-index:100;background-color: rgba(0,0,0,0.5);line-height:15px;top:0;right:0;`
    cloBtn.innerHTML = "<span style='color:#fff;'>x</span>"
    cloBtn.onclick = () => {
      this.onRemove();
    }
    container.appendChild(cloBtn);

    parentMap.getContainer().appendChild(container);

    if (opts.id !== "") {
      container.id = opts.id;
    }

    return container;
  }

  _preventDefault(e) {
    e.preventDefault();
  }
}
